import { stat, copyFile, unlink, readdir } from 'fs/promises';
import moment from 'moment';
import pino from 'pino';
import config from './config.js';
import ZimuApi from './api/ZimuApi.js';
import PushApi from './api/PushApi.js';
import FFmpegApi from './api/FFmpegApi.js';

const logger = pino({ transport: { target: 'pino-pretty' } });

let liveMap = new Map();
let authors = [];

for (let i = 0; i < config.biligo.authorIds.length; ++i) {
    const authorId = config.biligo.authorIds[i];
    const res = await ZimuApi.findAuthorById(authorId);
    const author = await res.json();
    logger.info(author);
    authors.push(author);
    liveMap.set(authorId, null);
}

while (true) {
    for (let i = 0; i < authors.length; ++i) {
        const author = authors[i];
        // 判断是否有正在直播的文件，如果有，先检查下播与否
        const liveValue = liveMap.get(author.id);
        if (liveValue) {
            const flvname = liveValue.name;
            const flvpath = liveValue.path;
            const flvsize = liveValue.size;
            const fileinfo = await stat(flvpath);
            // 如果文件大小不再变化，说明下播了
            logger.info(`原文件大小:${flvsize},现文件大小:${fileinfo.size}`);
            if (fileinfo.size <= flvsize) {
                logger.info('下播');

                logger.info('准备处理数据转换和迁移');

                const m4aname = `${liveValue.clipId}.m4a`;
                const mp4name = flvname.replace('.flv', '.mp4');

                const dstm4apath = `${config.rec.m4a}/${m4aname}`;
                const dstflvpath = `${config.rec.mp4}/${flvname}`;
                const dstmp4path = `${config.rec.mp4}/${mp4name}`;

                const rootflvpath = flvpath.replace('/live/', '/record/');
                const rootmp4path = rootflvpath.replace('.flv', '.mp4');

                // 复制flv到待转区
                await copyFile(flvpath, dstflvpath);
                logger.info(`复制${flvpath}到${dstflvpath}结束`);

                const duration = await FFmpegApi.getDuration(dstflvpath);
                const message = `${author.name},${flvname},${duration}`;
                if (duration <= "00:10:00.00") {
                    // 时间太短就不要了
                    logger.info(`时间过短:${message},不得低于10分钟`);
                    PushApi.push('时间过短', message);

                    // 重试10次
                    for (let i = 0; i < config.web.retry; ++i) {
                        try {
                            await ZimuApi.deleteClip(liveValue.clipId);
                            break;
                        } catch (ex) {
                            ctx.logger.error(ex);
                        }
                        await new Promise((res, rej) => {
                            setTimeout(() => { res(); }, 3000);
                        });
                    }
                } else {
                    logger.info('开始flv转m4a');
                    await FFmpegApi.toM4A(dstflvpath, dstm4apath);
                    logger.info('生成m4a结束');

                    // try {
                    //     logger.info(`生成一图MP4:${dstimagemp4path}开始`);
                    //     await FFmpegApi.toImageMP4(dstm4apath, dstimagemp4path);
                    //     logger.info(`生成一图MP4:${dstimagemp4path}结束`);
                    //     const imageMp4Title = flvname.replace(`.flv`, ``).replace(`-${author.name}-`, `-${author.id}-`);
                    //     await BiliupApi.upload(dstimagemp4path, imageMp4Title);
                    //     logger.info(`上传视频${dstimagemp4path}结束`);
                    // } catch (ex) {
                    //     // 就算上传失败，也不影响接下来的操作
                    //     logger.error(ex);
                    // }

                    logger.info('开始flv转mp4');
                    await FFmpegApi.toMP4(dstflvpath, dstmp4path);
                    logger.info('flv转mp4结束');

                    // 复制mp4到record区
                    logger.info(`复制${dstmp4path}到${rootmp4path}开始`);
                    await copyFile(dstmp4path, rootmp4path);
                    logger.info(`复制${dstmp4path}到${rootmp4path}结束`);

                    await unlink(dstflvpath);
                    logger.info(`删除${dstflvpath}结束`);

                    for (let i = 0; i < config.web.retry; ++i) { // 重试10次
                        try {
                            const newClip = await ZimuApi.updateClip(liveValue.clipId, { type: 3 });
                            logger.info('clip更新后:');
                            logger.info(newClip);
                            break;
                        } catch (ex) {
                            logger.error(ex);
                        }
                        await new Promise((res, rej) => {
                            setTimeout(() => { res(); }, 3000);
                        });
                    }

                }

                await unlink(flvpath);
                logger.info(`删除${flvpath}结束`);

                // await rename(flvpath, `${flvpath}.bak`);
                liveMap.set(author.id, null);
            } else {
                // 更新保存的当前字节数
                liveMap.get(author.id).size = fileinfo.size;
            }
        } else {
            // 如果liveMap中没有内容，说明这一时刻没有发现正在开播的文件，需要去文件夹中找
            const yyyyMM = moment().format('yyyy-MM');
            const liveDir = `${config.rec.live}/${author.name}/${yyyyMM}`;
            logger.info(`check ${liveDir}`);

            const files = await readdir(liveDir);
            for (let j = 0; j < files.length; ++j) {
                const file = files[j];
                if (!file.endsWith('.flv')) {
                    continue;
                }
                // 如果此时发现flv文件，说明已经开始直播，将flvpath和flvsize记录到liveMap中
                logger.info(`开播:${file}`);
                const flvpath = `${liveDir}/${file}`;
                const flvinfo = await stat(flvpath);
                
                const tmp = file.split('-');
                const date = tmp[0];
                const time = tmp[1];
                const datetime = `${date.substring(0,4)}-${date.substring(4,6)}-${date.substring(6,8)} ${time.substring(0,2)}:${time.substring(2,4)}:${time.substring(4,6)}`;
                const title = tmp[3].substring(0, tmp[3].length - 4);
                const clip = {
                    authorId:   author.id,
                    title:      title,
                    datetime:   datetime,
                    cover:      "",
                    type:       4
                };

                // 重试n次
                for (let i = 0; i < config.web.retry; ++i) {
                    try {
                        const newClip = await ZimuApi.insertClip(clip);
                        liveMap.set(author.id, {name:file, path:flvpath, size:flvinfo.size, clipId:newClip.id});
                        logger.info('创建新clip');
                        logger.info(newClip);
                        PushApi.push('录制开始', `${author.name},${title}`);
                        break;
                    } catch (ex) {
                        logger.error(ex);
                    }
                    await new Promise((res, rej) => {
                        setTimeout(() => { res(); }, 3000);
                    });
                }
                break;
            }
        }
    }
    await new Promise((res, rej) => {
        setTimeout(() => { res(); }, config.biligo.interval);
    });
}